#include "CommandExecutor.h"

#include <iostream>
#include <cstring>
#include <bitset>
#include <cstdlib>
#include <linux/rtc.h>
#include <sys/ioctl.h>

#include "HalUtility.h"
#include "CommandParser.h"
#include "LoopControlInfo.h"
#include "LoopStatus.h"
#include "LoopCommandType.h"
#include "LoopControlInfoManager.h"
#include "ExtendDeviceManager.h"
#include "PowerMonitor.h"
#include "BasicDevice.h"
#include "DoorAlertor.h"
#include "CurrentVoltageManager.h"
#include "MachineDependents.h"
#include "AcSwitchDetector.h"
#include "LoopManager.h"

#include "NetworkManager.h"
#include "VideoController.h"
#include "UriInfo.h"
#include "FirmwareUpdater.h"
#include "Authenticator.h"
#include "GpsSensor.h"
#include "InnerTemperatureMonitor.h"
#include "LuxSensor.h"
#include "YmxVideoController.h"
#include "IotGatway.h"


CommandExecutor::CommandExecutor() : mloopManager(LoopManagerSingleton::instance()) {
}

void CommandExecutor::onSpecialTimeOperated(std::string& detailCmd, std::string& result) {
//    LoopSchedulerSingleton::instance().clear();

    LoopControlInfoManager& loopControlInfoManager = LoopControlInfoManagerSingleton::instance();
    if (detailCmd.length() >= 10) {
        LoopControlInfoList loopControlInfos;// = loopControlInfoManager.getLoopControlInfos();
        std::string::size_type index = detailCmd.find("skip");
        if (std::string::npos == index) {
            const char* delimiter = "][";
            const char* secondString;
            // std::string::size_type prevIndex = 0;
            //for (index = detailCmd.find("]["); index != std::string::npos; prevIndex = index, index = detailCmd.find("][", index)){

            LoopControlInfo* pLoopControlInfo;
            std::tm dateTm;
            std::memset(&dateTm, 0, sizeof (dateTm));
            std::time_t dateT;
            std::size_t length;
            uint64_t bits;
//            const LoopStatus* pStart;
            int actualLength = 0;
            char* pTokenContext;
            const char* pCommandString = strtok_r(&detailCmd[0], delimiter, &pTokenContext);
            while(pCommandString) {
                length = std::strlen(pCommandString);
                if (15 < length) {
                    bits = std::strtoull(pCommandString + 14, nullptr, 16);
                    std::bitset<8 * sizeof bits> commandBits(bits);// >> (4 * (length - 17))
                    actualLength = (length - 14) * 4;
//                    pStart = commandBits.to_string<LoopStatus>(LoopStatus::AUTO_OFF, LoopStatus::AUTO_ON).data() + (8 * sizeof bits - actualLength);
                    //LOG_DEDUG("actualLength:%d, offset:%d, bitString:%s, pStart:%s" , actualLength, 8 * sizeof bits - actualLength, commandBits.to_string<LoopStatus>(LoopStatus::AUTO_OFF, LoopStatus::AUTO_ON).data(), pStart);
                    pLoopControlInfo = new(actualLength) LoopControlInfo(commandBits.to_string<LoopStatus>(LoopStatus::AUTO_OFF, LoopStatus::AUTO_ON).data() + (8 * sizeof bits - actualLength), actualLength);

                    secondString = strptime(pCommandString, DateTimeUtility::DATE_FORMAT.data(), &dateTm);
                    dateT = mktime(&dateTm);
                    dateT += std::strtoll(secondString, nullptr, 10);
                    pLoopControlInfo->beginTime = DateTimeUtility::to_ClockTime(dateT);
                    pLoopControlInfo->duration = DateTimeUtility::ClockTime_t::zero();
                    pLoopControlInfo->commandType = LoopCommandType::OFFLINE_COMMAND;
                    loopControlInfos.emplace_back(pLoopControlInfo, LoopControlInfo::releaseMemory);

                    pCommandString = strtok_r(nullptr, delimiter, &pTokenContext);
                } else {
                    LOG_ERROR("offline command data error:%s", pCommandString);
                    break;
                }
            }
        }

        LoopControlInfoManager::save(detailCmd.substr(0, 6), loopControlInfos);

//        loopControlInfoManager.clear();

//        INetwork network;
//        LoopSchedulerSingleton::instance().offline(&network);//TODO for test, if release, remove it
    } else {
        LOG_ERROR("离线指令错误:%s", detailCmd.data());
    }
}

/**
 * B指令 申请本地储存数据操作
 *
 * @param conn 当前连接
 * @param detailCmd, std::string& result 指令内容
 */
void CommandExecutor::onRequestOfflineCommand(const std::tm dateTime, std::string& result) {

    DateTimeUtility::toYearMouthString(dateTime, result);
}



void CommandExecutor::onDeleteLocalSwitch(std::string& result) {
    LoopControlInfoManagerSingleton::instance().remove();

    mparentCommandParser->requestOfflineCommand();
}



void CommandExecutor::onWriteTime(const NetworkStringView& detailCmd) {

    std::tm nowTm;
    std::memset(&nowTm, 0, sizeof (nowTm));
    NetworkStringView::value_type* pEnd = strptime(detailCmd.data(), DateTimeUtility::DATE_TIME_FORMAT.data(), &nowTm);
    if (pEnd) {
        setSystemTime(nowTm);
    }
//    std::string result(":");
//    std::cout << __FILE__ << ":" <<__FUNCTION__ << DateTimeUtility::timeToString(nowTime, DateTimeUtility::DATE_TIME_FOR_READ_FORMAT, result) << "end:" <<pEnd << std::endl;
}


void CommandExecutor::setSystemTime(std::tm& tmTime) {
    std::time_t nowTime = std::mktime(&tmTime);
    std::time_t oldTime = std::time(nullptr);
    const std::time_t timeDistance = nowTime - oldTime;
    int returnValue = 0;

    returnValue = ::stime(&nowTime);
    if (returnValue < 0) {
        std::string errorMessage{"stime failed,"};
        buildErrorMessage(returnValue, errno, errorMessage);
        LOG_DEDUG(errorMessage.data());
    }


    tmTime.tm_isdst = 0;

    BasicDevice rtc{"/dev/rtc", O_WRONLY | O_CLOEXEC};

    if ((returnValue = ioctl(rtc.getDeviceFd(), RTC_SET_TIME, &tmTime)) < 0) {
        std::string errorMessage{"set rtc failed,"};
        buildErrorMessage(returnValue, errno, errorMessage);
        LOG_DEDUG(errorMessage.data());
    }
    LOG_DEDUG("setSystemTime completed");

    if (23 * 3600 < timeDistance || -23 * 3600 > timeDistance) {
        std::string result;
        //CommandExecutorSingleton::instance().onDeleteLocalSwitch(result);

        mparentCommandParser->requestOfflineCommand();
    }
}



void CommandExecutor::onVersion(std::string& result) {

    result = mconfigManager.getVersionInfo().firmwareVersionString;
}



void CommandExecutor::onCheckSwitch(std::string& result) {
    mloopManager.getLoopStatus(result);
}



void CommandExecutor::onChannelOperated(LoopControlInfoPtr command, const std::time_t delaySeconds, std::string& result) {

    mloopManager.changeAutoLoopStatus(command, delaySeconds);
}


size_t CommandExecutor::onChannel() {
    return mloopManager.updatePortCount();
}



void CommandExecutor::onNetworkState(const std::string& detailCmd, std::string& result) {
    NetworkManager& networkManager = NetworkManagerSingleton::instance();         //
    std::string signal = networkManager.mpactiveNetwork->getSignalStrength();
    if (signal.empty()) {
        throw BUILD_EXCEPTION_MESSAGE(FirmwareError::NETWORK_SIGNAL_ERROR, "can not get signal strength");
    }
    result = networkModeVector->at(networkManager.mtype);
    result.append(1, '_').append(signal);

}



void CommandExecutor::onCurrentAndVoltage(const std::string& detailCmd, std::string& result) {
    CurrentVoltageManager& currentVoltageManager = CurrentVoltageManagerSingleton::instance();

    currentVoltageManager.updateInformation();

    ICurrentVoltageDetector* pVoltageCurrentDetector;
    ExtendDevicePtr extendDevicePtr;
    const CurrentVoltageInfo* pcurrentVoltageInfo = nullptr;
    const CurrentVoltageInfo* pEnd = nullptr;
    std::ostringstream oss;
    for (ExtendDeviceWeakPtr& loopDeviceWeakPtr : *currentVoltageManager.mpControllers) {
        extendDevicePtr = loopDeviceWeakPtr.lock();
        if (!extendDevicePtr) {
            continue;
        }

        pVoltageCurrentDetector = static_cast<ICurrentVoltageDetector*> (&*extendDevicePtr);
        pcurrentVoltageInfo = pVoltageCurrentDetector->getCurrentVoltageInfos();
        pEnd = pcurrentVoltageInfo + pVoltageCurrentDetector->mportCount;

        for (const CurrentVoltageInfo* iterator = pcurrentVoltageInfo; iterator != pEnd; ++iterator) {
            oss << '[' << iterator->portNo << '_'<< iterator->phase << '/' << iterator->voltage << '/' << iterator->current <<']';
        }
    }
    result = oss.str();
}


//java: <W_456621.00_[A/220/000.0][B/220/000.0][C/220/000.0]_OK>
//<W_1237567.00_12345.00/0.99_[A/220/000.00][B/220/000.00][C/220/000.00]>
void CommandExecutor::onPower(const std::string& detailCmd, std::string& result) {
    std::vector<ExtendDeviceWeakPtr>* pControllers = &ExtendDeviceManagerSingleton::instance().getExtendDevices(ExtendDeviceEnum::POWER);
    if (pControllers->empty()) {
        return;
    }

    ExtendDevicePtr extendDevicePtr = pControllers->front().lock();
    if (extendDevicePtr) {

        PowerMonitor* pPowerMonitor = static_cast<PowerMonitor*> (&*extendDevicePtr);
        pPowerMonitor->updateInformation();

        result = pPowerMonitor->mkwh;
//        result.append(1, '_');
//        result.append(pPowerMonitor->mpower);
//        result.append(1, '/');
//        result.append(pPowerMonitor->mcoefficient);
        result.append( "_[");
        CurrentVoltageInfo* voltageInfo = &pPowerMonitor->maPhase;
        result.append(1, voltageInfo->phase).append(1, '/').append(voltageInfo->voltage).append(1, '/').append(voltageInfo->current).append("][");

        voltageInfo = &pPowerMonitor->mbPhase;
        result.append(1, voltageInfo->phase).append(1, '/').append(voltageInfo->voltage).append(1, '/').append(voltageInfo->current).append("][");

        voltageInfo = &pPowerMonitor->mcPhase;
        result.append(1, voltageInfo->phase).append(1, '/').append(voltageInfo->voltage).append(1, '/').append(voltageInfo->current).append(1, ']');
    }

}



void CommandExecutor::onRequestDeviceId(std::string& result) {
    result = mconfigManager.getVersionInfo().uuidString;

    ++mparentCommandParser->mparentCommandDispatcher->mserverReady;
    /*  comment for not request when system online 20210323
        if (1 == mparentCommandParser->mparentCommandDispatcher->mserverReady) {
            mparentCommandParser->requestOfflineCommand();
        }
        */
}



void  CommandExecutor::onDoorStatus(const std::string& detailCmd, std::string& result) {
    std::vector<ExtendDeviceWeakPtr>* pControllers = &ExtendDeviceManagerSingleton::instance().getExtendDevices(ExtendDeviceEnum::DOOR_ALERTOR);
    if (pControllers->empty()) {
        throw BUILD_EXCEPTION_MESSAGE(FirmwareError::DOOR_ALERTOR_ERROR, "no door alertor");
    }

    ExtendDevicePtr extendDevicePtr = pControllers->front().lock();
    if (extendDevicePtr) {
        DoorAlertor* pDoorAlertor = static_cast<DoorAlertor*> (extendDevicePtr->getDevice(ExtendDeviceEnum::DOOR_ALERTOR));
        if (DoorStatus::ERROR != pDoorAlertor->mdoorStatus) {

            result.append(doorStatusVector->at(static_cast<StringVector::size_type> (pDoorAlertor->mdoorStatus)));//
        } else {
            throw BUILD_EXCEPTION_MESSAGE(FirmwareError::DOOR_ALERTOR_ERROR, "can not get door alertor status");
        }
    }
}



void CommandExecutor::onAcSwitchStatus(std::string& switchMode, std::string& loopSwitchStatus) {
    std::vector<ExtendDeviceWeakPtr>* pControllers = &ExtendDeviceManagerSingleton::instance().getExtendDevices(ExtendDeviceEnum::AC_SWITCH_DETECTOR);
    if (pControllers->empty()) {
        throw BUILD_EXCEPTION_MESSAGE(FirmwareError::AC_SWITCH_DETECTOR_ERROR, "no ac switch detector");
    }

    ExtendDevicePtr extendDevicePtr = pControllers->front().lock();
    if (extendDevicePtr) {
        AcSwitchDetector* pswitchDetector = static_cast<AcSwitchDetector*> (extendDevicePtr->getDevice(ExtendDeviceEnum::AC_SWITCH_DETECTOR));

        std::string loopStatusString;
        mloopManager.getLoopStatus(loopStatusString);

        pswitchDetector->analysisSwitchStatus(loopStatusString);
        switchMode = pswitchDetector->mswitchMode;
        loopSwitchStatus = pswitchDetector->mloopSwitchStatus;
    }

}


void CommandExecutor::onVideoControl(VideoPlayInfo& videoPlayInfo, std::string& result) {

    std::vector<ExtendDeviceWeakPtr>* pControllers = &ExtendDeviceManagerSingleton::instance().getExtendDevices(ExtendDeviceEnum::VIDEO_CONTROLLER);
    if (pControllers->empty()) {
        throw BUILD_EXCEPTION_MESSAGE(FirmwareError::VIDEO_PLAY_ERROR, "no video server");
    }


    ExtendDevicePtr extendDevicePtr = pControllers->front().lock();
    if (extendDevicePtr) {
        VideoController* pvideoController = static_cast<VideoController*> (&*extendDevicePtr);
        if (false == pvideoController->configAndPlay(videoPlayInfo)) {
            throw BUILD_EXCEPTION_MESSAGE(FirmwareError::VIDEO_PLAY_ERROR, "onVideoControl failed");
        }
    }

    /*
    YmxVideoController ymxVideoController(ExtendDeviceEnum::VIDEO_CONTROLLER, "");
    ymxVideoController.configAndPlay(videoPlayInfo);
    */

}

void CommandExecutor::onDownloadFile(const UriInfo& uriInfo, std::string& result) {
    if (mpFileDownloader) {
        throw BUILD_EXCEPTION_MESSAGE(FirmwareError::UPDATE_FIRMWARE_ERROR, "downloader is running alreadly");
    }

    FileDownloader* pFileDownloader = new FileDownloader();
    pFileDownloader->initialize(uriInfo, DOWNLOAD_PATHNAME, std::bind(&CommandExecutor::updateFirmware, this, std::placeholders::_1, std::placeholders::_2));

    mpFileDownloader = pFileDownloader;
    pFileDownloader->getWorkThread().start();
}

bool CommandExecutor::updateFirmware(FileDownloader& downloader, const std::string& pathname) {
//    FileDownloaderPtr fileDownloaderPtr = mpFileDownloader;
//    mpFileDownloader.reset();

    LOG_DEDUG("download complete! unpacking ...[%s]", pathname.data());
    FirmwareUpdater& updater = FirmwareUpdaterSingleton::instance();
    if (updater.unpack()) {
        bool result = updater.runUpdateScript();
        updater.clearTemp();
        if (result) {
            LOG_INFO("update seccussfully, system restarting...");
            ::sync();

            ::exit(0);
        } else {
            LOG_ERROR("runUpdateScript failed, update firmware failed!");
        }
    } else {
        LOG_ERROR("unpack failed, update firmware failed!");
    }

    mpFileDownloader = nullptr;
    return true;
}

void CommandExecutor::lock(std::string& result) {
    Authenticator& authenticator = AuthenticatorSingleton::instance();

    authenticator.mpermit = false;
}

void CommandExecutor::unlock(const std::time_t delaySeconds, std::string& result) {

    Authenticator& authenticator = AuthenticatorSingleton::instance();
    authenticator.authenticate(delaySeconds);
}




void CommandExecutor::updatePassword(const std::string password, std::string& result) {
    mconfigManager.getConfigInfo().password = password;

    mconfigManager.saveConfigInfo();
}


/**
	 * @return 获取格式化后的位置 如12.266E_125.36N
	 */
void CommandExecutor::onNewRequestLocation(const std::string& detailCmd, std::string& result) {
    std::vector<ExtendDeviceWeakPtr>* pControllers = &ExtendDeviceManagerSingleton::instance().getExtendDevices(ExtendDeviceEnum::GPS);
    if (pControllers->empty()) {
        throw BUILD_EXCEPTION_MESSAGE(FirmwareError::DEVICE_MODULE_OFFLINE_ERROR, "no gps");
    }

    ExtendDevicePtr extendDevicePtr = pControllers->front().lock();
    if (extendDevicePtr) {
        GpsSensor* pgpsController = static_cast<GpsSensor*> (extendDevicePtr->getDevice(ExtendDeviceEnum::GPS));

        result.append(pgpsController->latitude).append(1, pgpsController->latitudeSymbol);
        result.append(1, '_').append(pgpsController->longitude).append(1, pgpsController->longitudeSymbol);
        result.append(1, '_').append(pgpsController->satelliteQuantity);
        result.append(1, '_').append(pgpsController->signalNoise);
    }
}



void CommandExecutor::onTemperature(const std::string& detailCmd, std::string& result) {
    std::vector<ExtendDeviceWeakPtr>* pControllers = &ExtendDeviceManagerSingleton::instance().getExtendDevices(ExtendDeviceEnum::TEMPERATURE);
    if (pControllers->empty()) {
        throw BUILD_EXCEPTION_MESSAGE(FirmwareError::DEVICE_MODULE_OFFLINE_ERROR, "no temperature sensor");
    }

    ExtendDevicePtr extendDevicePtr = pControllers->back().lock();
    if (extendDevicePtr) {
        InnerTemperatureMonitor* ptemperatueMonitor = static_cast<InnerTemperatureMonitor*> (extendDevicePtr->getDevice(ExtendDeviceEnum::TEMPERATURE));

        result = ptemperatueMonitor->mtemperature.second;
        result.append(1, '_');
        if (detailCmd.empty()) {
            result.append(ptemperatueMonitor->mthreshold.second);
            result.append("_00");
        } else {
            result.append(detailCmd);

            if (std::string::npos == detailCmd.find("ALARM")) {
                result.append("_00");

                ptemperatueMonitor->mthreshold.first = std::strtof(detailCmd.data(), nullptr);
                ptemperatueMonitor->mthreshold.second = detailCmd;

            }
        }


    }
}



void CommandExecutor::onSunLight(const std::string& detailCmd, std::string& result) {
    std::vector<ExtendDeviceWeakPtr>* pControllers = &ExtendDeviceManagerSingleton::instance().getExtendDevices(ExtendDeviceEnum::LUX);
    if (pControllers->empty()) {
        throw BUILD_EXCEPTION_MESSAGE(FirmwareError::DEVICE_MODULE_OFFLINE_ERROR, "no temperature sensor");
    }

    ExtendDevicePtr extendDevicePtr = pControllers->back().lock();
    if (extendDevicePtr) {
        LuxSensor* pluxSensor = static_cast<LuxSensor*> (extendDevicePtr->getDevice(ExtendDeviceEnum::LUX));
        pluxSensor->updateInformation();
        result = pluxSensor->mluxString;
    }
}



void CommandExecutor::onExtendDeviceStatus(std::vector<ExtendDeviceInfo>& result) {
    const ExtendDeviceWeakPtr* pExtendDevices = ExtendDeviceManagerSingleton::instance().getAllOnlineExtendDevices();

    ExtendDevicePtr extendDevicePtr;
    for (int i = 0; i < MDConst::DEFAULT_CHANNEL_COUNT; ++i) {
        extendDevicePtr = pExtendDevices[i].lock();
        if (extendDevicePtr) {
            result.emplace_back(extendDevicePtr->mdeviceType.name, extendDevicePtr->mversionString);
        } else {
            result.emplace_back(ExtendDeviceEnum::NO_DEVICE.name, StringUtility::EMPTY_STRING);
        }
    }
}


void CommandExecutor::onForwardData(const VerbInfo& verbInfo,  VerbResult& result) {
    IotGatway iotGatway;
    try {
        iotGatway.doVerb(verbInfo, result);
    }   catch (std::system_error& systemError) {
        result.errorCode = systemError.code().value();
        result.errorMessage = systemError.what();
    } catch (std::exception& systemError) {
        result.errorCode = static_cast <int32_t>(FirmwareError::IOTGATWAY_COMMAND_ERROR);
        result.errorMessage = systemError.what();
    }
}




